/**
 * Copyright (C) 2009 fgrilli <federico.grilli@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
package com.google.code.mgnlgroovy.scheduler;

import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import groovy.lang.Script;
import info.magnolia.context.MgnlContext;
import info.magnolia.context.SimpleContext;

import java.util.Map;

import javax.jcr.RepositoryException;

import org.apache.commons.lang.StringUtils;
import org.codehaus.groovy.control.CompilationFailedException;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.code.mgnlgroovy.scheduler.manager.JobDefinitionManager;


/**
 * A MgnlContext-aware Groovy Job 
 * @author fgrilli
 * @version $Id: GroovyJob.java 38 2009-04-20 16:27:38Z federico.grilli $
 */
public class GroovyJob implements Job
{

    private static final Logger log = LoggerFactory.getLogger(GroovyJob.class);

    private JobDefinitionManager jobDefinitionManager = JobDefinitionManager.Factory.getInstance();

    /**
     * @see org.quartz.Job#execute(org.quartz.JobExecutionContext)
     */
    public void execute(JobExecutionContext jobCtx) throws JobExecutionException
    {
        String jobName = jobCtx.getJobDetail().getName();
        log.info("starting job [{}]", jobName);
        Map jobData = jobCtx.getJobDetail().getJobDataMap();

        // init context
        MgnlContext.setInstance(new SimpleContext(MgnlContext.getSystemContext()));
        String groovyScript = (String) jobData.get(SchedulerConsts.CONFIG_JOB_GROOVY);

        if (StringUtils.isEmpty(groovyScript))
        {
            String msg = "can't find groovy script for job " + jobName;
            log.error(msg);
            throw new JobExecutionException(msg, false);
        }

        log.debug("executing script {}", groovyScript);

        Object retVal;
        JobDefinition jd = null;

        try
        {
            jd = jobDefinitionManager.getJobDefinitionByName(jobName);
            if (jd != null)
            {
                jd.setTerminatedWithError(false);
            }
            Binding binding = new Binding((Map) jobData.get(SchedulerConsts.CONFIG_JOB_PARAMS));
            GroovyShell shell = new GroovyShell(binding);
            Script script = shell.parse(groovyScript);
            retVal = script.run();
            log.info("job [{}] executed successfully , Groovy script returned {}", new Object[]{jobName, retVal });
        }
        catch (CompilationFailedException e)
        {
            log.error("An error occurred while parsing the script. Error message is {}", new Object[]{e.getMessage() });
            if (jd != null)
            {
                jd.setTerminatedWithError(true);
            }
            throw new JobExecutionException("can't execute job " + jobName, e, false);
        }
        catch (Exception e)
        {
            log.error(
                "An error occurred while executing the script. Error message is {}",
                new Object[]{e.getMessage() });
            if (jd != null)
            {
                jd.setTerminatedWithError(true);
            }
            throw new JobExecutionException("can't execute job " + jobName, e, false);
        }
        finally
        {
            MgnlContext.setInstance(null);
            try
            {
                if (jd != null)
                {
                    jd.setLastFireTime(jobCtx.getFireTime().getTime());
                    jd.setNextFireTime(jobCtx.getNextFireTime().getTime());
                    jobDefinitionManager.saveOrUpdateJobDefinition(jd);
                }
            }
            catch (RepositoryException e)
            {
                log.error(e.getMessage());
            }
        }
    }
}